from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_current_user, get_db
from app.models.user import PartnerProfile, User
from app.models.relationship import Relationship
from app.models.memory_node import MemoryNode
from app.models.memory_edge import MemoryEdge
from app.models.memory_node import MemoryNode
from app.models.memory_edge import MemoryEdge
from app.schemas import user as user_schema
from app.api.response import success_response
from app.core.config import settings

router = APIRouter(redirect_slashes=False)


@router.get("/me")
async def get_me(
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
) -> dict:
  detail = user_schema.UserDetail.model_validate(current_user, from_attributes=True)
  # 全面切图谱：从图谱聚合 prefs（无 JSON 依赖）
  data = detail.model_dump(mode='json')
  rid = current_user.active_relationship_id
  likes: list[str] = []
  dislikes: list[str] = []
  topics: list[str] = []
  person = await session.scalar(
    select(MemoryNode).where(
      MemoryNode.user_id == current_user.id,
      MemoryNode.relationship_id == rid,
      MemoryNode.type == 'person',
      MemoryNode.label.in_(['我','self']),
    )
  )
  if person:
    edges = (await session.scalars(
      select(MemoryEdge).where(
        MemoryEdge.user_id == current_user.id,
        MemoryEdge.relationship_id == rid,
        MemoryEdge.src_id == person.id,
      )
    )).all()
    for e in edges:
      node = await session.get(MemoryNode, e.dst_id)
      if not node:
        continue
      if e.type == 'prefers' and node.type == 'preference':
        likes.append(node.label)
      elif e.type == 'avoids' and node.type == 'preference':
        dislikes.append(node.label)
      elif e.type == 'mentions' and node.type == 'topic':
        topics.append(node.label)
  data['prefs'] = {
    'likes': list(dict.fromkeys(likes)),
    'dislikes': list(dict.fromkeys(dislikes)),
    'topics': list(dict.fromkeys(topics)),
  }
  # 伴侣显示昵称与关系开始时间：来自关系表与对方用户资料
  partner_display_name = None
  relationship_started_at = None
  if rid:
    rel = await session.get(Relationship, rid)
    if rel:
      relationship_started_at = rel.confirmed_at.isoformat() if rel.confirmed_at else None
      other: User | None = None
      if rel.initiator_id == current_user.id:
        other = rel.partner
      elif rel.partner_id == current_user.id:
        other = rel.initiator
      if other:
        partner_display_name = other.nickname or other.username or other.email
  data['partner_display_name'] = partner_display_name
  data['relationship_started_at'] = relationship_started_at
  # 覆盖 partner_profile.notification_prefs：从 ORM 的 notification_prefs_json 提供
  if current_user.partner_profile:
    pp = current_user.partner_profile
    if 'partner_profile' not in data or data['partner_profile'] is None:
      data['partner_profile'] = {}
    data['partner_profile']['notification_prefs'] = pp.notification_prefs_json
  return success_response(data)


@router.put("/me/preferences")
async def update_preferences(
  payload: user_schema.UpdatePreferencesRequest,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
) -> dict:
  # 将 payload.prefs 中的 likes/dislikes/topics 映射为图谱边：prefers/avoids/mentions
  rid = current_user.active_relationship_id
  person = await session.scalar(
    select(MemoryNode).where(
      MemoryNode.user_id == current_user.id,
      MemoryNode.relationship_id == rid,
      MemoryNode.type == 'person',
      MemoryNode.label == 'self',
    )
  )
  if not person:
    person = MemoryNode(user_id=current_user.id, relationship_id=rid, type='person', label='self', props_json={})
    session.add(person)
    await session.flush()

  prefs = payload.prefs or {}
  likes = [str(x).strip() for x in (prefs.get('likes') or []) if str(x).strip()]
  dislikes = [str(x).strip() for x in (prefs.get('dislikes') or []) if str(x).strip()]
  topics = [str(x).strip() for x in (prefs.get('topics') or []) if str(x).strip()]

  async def upsert_edge_to_label(etype: str, label: str, ntype: str) -> None:
    node = await session.scalar(
      select(MemoryNode).where(
        MemoryNode.user_id == current_user.id,
        MemoryNode.relationship_id == rid,
        MemoryNode.type == ntype,
        MemoryNode.label == label,
      )
    )
    if not node:
      node = MemoryNode(user_id=current_user.id, relationship_id=rid, type=ntype, label=label, props_json={})
      session.add(node)
      await session.flush()
    edge = await session.scalar(
      select(MemoryEdge).where(
        MemoryEdge.user_id == current_user.id,
        MemoryEdge.relationship_id == rid,
        MemoryEdge.type == etype,
        MemoryEdge.src_id == person.id,
        MemoryEdge.dst_id == node.id,
      )
    )
    if not edge:
      session.add(MemoryEdge(user_id=current_user.id, relationship_id=rid, type=etype, src_id=person.id, dst_id=node.id, props_json={}))

  # 先清理现有对应类型的边，再写入新边
  existing = (await session.scalars(
    select(MemoryEdge).where(
      MemoryEdge.user_id == current_user.id,
      MemoryEdge.relationship_id == rid,
      MemoryEdge.src_id == person.id,
      MemoryEdge.type.in_(['prefers','avoids','mentions']),
    )
  )).all()
  for e in existing:
    await session.delete(e)
  await session.flush()

  for v in likes:
    await upsert_edge_to_label('prefers', v, 'preference')
  for v in dislikes:
    await upsert_edge_to_label('avoids', v, 'preference')
  for v in topics:
    await upsert_edge_to_label('mentions', v, 'topic')
  await session.commit()

  # 返回最新用户详情
  detail = user_schema.UserDetail.model_validate(current_user, from_attributes=True)
  data = detail.model_dump(mode='json')
  data['prefs'] = {'likes': likes, 'dislikes': dislikes, 'topics': topics}
  return success_response(data)


@router.put("/me")
async def update_profile(
  payload: user_schema.UpdateProfileRequest,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
) -> dict:
  if payload.username and payload.username != current_user.username:
    current_user.username = payload.username
  if payload.nickname is not None and payload.nickname != current_user.nickname:
    current_user.nickname = payload.nickname

  if payload.partner_profile:
    if current_user.partner_profile:
      profile = current_user.partner_profile
      profile.partner_name = payload.partner_profile.partner_name
      profile.relationship_start_date = payload.partner_profile.relationship_start_date
      profile.timezone = payload.partner_profile.timezone
      profile.notification_prefs_json = payload.partner_profile.notification_prefs
    else:
      profile = PartnerProfile(
        user_id=current_user.id,
        partner_name=payload.partner_profile.partner_name,
        relationship_start_date=payload.partner_profile.relationship_start_date,
        timezone=payload.partner_profile.timezone,
        notification_prefs_json=payload.partner_profile.notification_prefs,
      )
      session.add(profile)

  session.add(current_user)
  await session.commit()
  await session.refresh(current_user)
  detail = user_schema.UserDetail.model_validate(current_user, from_attributes=True)
  data = detail.model_dump(mode='json')
  if current_user.partner_profile:
    data['partner_profile'] = data.get('partner_profile') or {}
    data['partner_profile']['notification_prefs'] = current_user.partner_profile.notification_prefs_json
  return success_response(data)
